package com.zhdl.modules.process.task;

import com.project.common.util.DelayUtil;
import com.zhdl.common.conf.TaskSchedulerConfig;

//import com.zhdl.modules.process.dto.ProcessVerify;
import com.zhdl.modules.process.common.ProcessVerify;
import com.zhdl.modules.process.dto.ProcessBean;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.util.TextUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.ScheduledFuture;

@Slf4j
@Data
public class CustomizeTask implements Runnable {
    public CustomizeTask(String name, String data, String method, Object object, ProcessBean processBean) {
        this.name = name;
        this.data = data;// 需要进行下一步 步数 -1 从当前流程第一步开始 -2 停止
        this.method = method;
        this.object = object;
        this.processBean = processBean;
    }

    public CustomizeTask(ProcessBean processBean) {
        this.processBean = processBean;
        this.name = processBean.getDesc();
        this.data = "-2";
    }

    private String name;    // 任务名字
    private String cron;    // 触发条件
    private String data;    // 传输的数据参数
    private String method;  // 需要调用的方法
    private Object object;
    private long sTime = 0;
    private ProcessBean processBean;
    private boolean allVerify = false;
    private boolean isTest = false;
    private int runCount = 0;
    private boolean firstVerify = true;
    private boolean start = true;
    private int reTyCount = 0;

    public void reTry() {
        if (reTyCount > processBean.getReTryCount()) {
            log.info("重试次数超过设置次数");
            stopTaskById(name);
            return;
        }
        reTyCount++;
        sTime = 0;
        processBean.setSTime(0);
        processBean.setETime(0);
        processBean.getProcessDo().doSomeThing();
        start = true;
    }

    @Override
    public void run() {
        if (!start) {
            log.info(name + "当前任务停止状态等待激活");
            return;
        }
        if (firstVerify) {
            log.info(name + "任务开始执行.....");
        }
        runCount++;
        if (sTime == 0) {
            sTime = System.currentTimeMillis();
            processBean.setSTime(sTime);
        }
        if (processBean.getTimeout() != -1) {
            if (System.currentTimeMillis() - sTime >= processBean.getTimeout()) {
                log.info(processBean.getDesc() + "超时!!");
                start = false;
                if (processBean.getProcessTimeout() != null) {
                    processBean.getProcessTimeout().timeout(processBean.getDesc() + "超时!!",processBean);
                    processBean.setRunStatus(-1);
                }
                if (processBean.isReTryDo()) {
                    reTry();
                }
                return;
            }
        }
        if (isTest) {
            if (System.currentTimeMillis() - sTime >= 5000) {
                processBean.setETime(System.currentTimeMillis());
                processBean.setProduceTime(((int) (processBean.getETime() - sTime)));
                checkAfter();
                return;
            }
        }
//        if (firstVerify && processBean.getFirstVerifyBefore() != null) {
//            processBean.getFirstVerifyBefore().beforeFirstVerify();
//        }
        if (processBean.getProcessVerify() == null) {
            processBean.setProcessVerify(() -> true);
        }
        boolean verity;
        if (processBean.getProcessVerifyList().size() > 1) {
            verifyNext(0);
            verity = allVerify;
        } else {
            verity = processBean.getProcessVerify().verity();
            if (runCount % 10 == 0) {
                log.info(processBean.getDesc() + "校验结果" + verity);
            }
        }
        firstVerify = false;
        if (verity) {
            processBean.setETime(System.currentTimeMillis());
            processBean.setProduceTime(((int) (processBean.getETime() - sTime)));
            checkAfter();
        }
    }

    private void verifyNext(int i) {
        if (i <= processBean.getProcessVerifyList().size() - 1) {
            ProcessVerify processVerify = processBean.getProcessVerifyList().get(i);
            boolean verity = processVerify.verity();
            if (runCount % 10 == 0) {
                log.info(processBean.getDesc() + "校验[" + i + "]---校验结果" + verity);
            }
            if (verity) {
                verifyNext(i + 1);
            }
        } else {
            allVerify = true;
        }
    }

    private void checkAfter() {
        if (data.equals("-2")) {
            log.info(name + "流程停止");
            stopTaskById(name);
            if (processBean.getAfterCurrentProcessDo() != null) {
                processBean.getAfterCurrentProcessDo().next(processBean.getStep());
            }
            return;
        }
        if (data.equals("0")) {
            log.info(name + "完成当前循环 开始下一个循环");
        } else {
            log.info(name + "完成任务:  " + processBean.getDesc() + "  耗时: " + processBean.getProduceTime());
        }
        if (processBean.getAfterVerify() != null) {
            processBean.getAfterVerify().afterVerify();
        }
        processBean.setRunStatus(0);
        stopTaskById(name);
        if (processBean.getAfterCurrentProcessDo() != null) {
            processBean.getAfterCurrentProcessDo().next(processBean.getStep());
        } else {
            if (!TextUtils.isEmpty(method)) {
                Reflection(object, object.getClass(), method, new Class[]{Integer.class}, Integer.parseInt(data));
            }
        }
    }

    public void stopTaskById(String taskId) {
        if (TaskSchedulerConfig.cache.isEmpty()) return;
        if (TaskSchedulerConfig.cache.get(taskId) == null) {
            DelayUtil.delayedExecution(500, new Runnable() {
                @Override
                public void run() {
                    stopTaskById(taskId);
                }
            });
            return;
        }
        ScheduledFuture scheduledFuture = TaskSchedulerConfig.cache.get(taskId);
        if (scheduledFuture != null) {
            scheduledFuture.cancel(true);   // 这里需要使用指定的 scheduledFuture 来停止当前的线程
            TaskSchedulerConfig.cache.remove(taskId);        // 移除缓存
        }
    }

    /*
     * 通过反射执行cclass的方法
     * @param   object  ---调到该方法的具体对象
     * @param   cclass  ---具体对象的class类型
     * @param   paramClasses ---反射方法中参数class类型
     * @param   methodName   ---反射方法的名称
     * @param   args    ----调用该方法用到的具体参数
     *
     *
     * */
    public static Object Reflection(Object object, Class<?> cclass, String methodName, Class<?>[] paramclasses, Object... args) {

        try {
            Method method = cclass.getMethod(methodName, paramclasses);
            return method.invoke(object, args);

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;

    }


}
